home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 002 / emacssrc.arc / INPUT.C < prev    next >
Encoding:
C/C++ Source or Header  |  1987-02-15  |  10.1 KB  |  490 lines

  1. /*    INPUT:    Various input routines for MicroEMACS 3.7
  2.         written by Daniel Lawrence
  3.         5/9/86                        */
  4.  
  5. #include    <stdio.h>
  6. #include    "estruct.h"
  7. #include    "edef.h"
  8.  
  9. /*
  10.  * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
  11.  * ABORT. The ABORT status is returned if the user bumps out of the question
  12.  * with a ^G. Used any time a confirmation is required.
  13.  */
  14.  
  15. mlyesno(prompt)
  16.  
  17. char *prompt;
  18.  
  19. {
  20.     char c;            /* input character */
  21.     char buf[NPAT];        /* prompt to user */
  22.  
  23.     for (;;) {
  24.         /* build and prompt the user */
  25.         strcpy(buf, prompt);
  26.         strcat(buf, " [y/n]? ");
  27.         mlwrite(buf);
  28.  
  29.         /* get the responce */
  30.         c = tgetc();
  31.  
  32.         if (c == ectoc(abortc))        /* Bail out! */
  33.             return(ABORT);
  34.  
  35.         if (c=='y' || c=='Y')
  36.             return(TRUE);
  37.  
  38.         if (c=='n' || c=='N')
  39.             return(FALSE);
  40.     }
  41. }
  42.  
  43. /*
  44.  * Write a prompt into the message line, then read back a response. Keep
  45.  * track of the physical position of the cursor. If we are in a keyboard
  46.  * macro throw the prompt away, and return the remembered response. This
  47.  * lets macros run at full speed. The reply is always terminated by a carriage
  48.  * return. Handle erase, kill, and abort keys.
  49.  */
  50.  
  51. mlreply(prompt, buf, nbuf)
  52.     char *prompt;
  53.     char *buf;
  54. {
  55.     return(nextarg(prompt, buf, nbuf, ctoec('\n')));
  56. }
  57.  
  58. mlreplyt(prompt, buf, nbuf, eolchar)
  59.  
  60. char *prompt;
  61. char *buf;
  62. int eolchar;
  63.  
  64. {
  65.     return(nextarg(prompt, buf, nbuf, eolchar));
  66. }
  67.  
  68. /*    ectoc:    expanded character to character
  69.         colapse the CTRL and SPEC flags back into an ascii code   */
  70.  
  71. ectoc(c)
  72.  
  73. int c;
  74.  
  75. {
  76.     if (c & CTRL)
  77.         c = c & ~(CTRL | 0x40);
  78.     if (c & SPEC)
  79.         c= c & 255;
  80.     return(c);
  81. }
  82.  
  83. /*    ctoec:    character to extended character
  84.         pull out the CTRL and SPEC prefixes (if possible)    */
  85.  
  86. ctoec(c)
  87.  
  88. int c;
  89.  
  90. {
  91.         if (c>=0x00 && c<=0x1F)
  92.                 c = CTRL | (c+'@');
  93.         return (c);
  94. }
  95.  
  96. /* get a command name from the command line. Command completion means
  97.    that pressing a <SPACE> will attempt to complete an unfinished command
  98.    name if it is unique.
  99. */
  100.  
  101. int (*getname())()
  102.  
  103. {
  104. #if    ST520 & LATTICE
  105. #define register        
  106. #endif
  107.     register int cpos;    /* current column on screen output */
  108.     register int c;
  109.     register char *sp;    /* pointer to string for output */
  110.     register NBIND *ffp;    /* first ptr to entry in name binding table */
  111.     register NBIND *cffp;    /* current ptr to entry in name binding table */
  112.     register NBIND *lffp;    /* last ptr to entry in name binding table */
  113.     char buf[NSTRING];    /* buffer to hold tentative command name */
  114.     int (*fncmatch())();
  115.  
  116.     /* starting at the beginning of the string buffer */
  117.     cpos = 0;
  118.  
  119.     /* if we are executing a command line get the next arg and match it */
  120.     if (clexec) {
  121.         if (macarg(buf) != TRUE)
  122.             return(FALSE);
  123.         return(fncmatch(&buf[0]));
  124.     }
  125.  
  126.     /* build a name string from the keyboard */
  127.     while (TRUE) {
  128.         c = tgetc();
  129.  
  130.         /* if we are at the end, just match it */
  131.         if (c == 0x0d) {
  132.             buf[cpos] = 0;
  133.  
  134.             /* and match it off */
  135.             return(fncmatch(&buf[0]));
  136.  
  137.         } else if (c == ectoc(abortc)) {    /* Bell, abort */
  138.             ctrlg(FALSE, 0);
  139.             TTflush();
  140.             return( (int (*)()) NULL);
  141.  
  142.         } else if (c == 0x7F || c == 0x08) {    /* rubout/erase */
  143.             if (cpos != 0) {
  144.                 TTputc('\b');
  145.                 TTputc(' ');
  146.                 TTputc('\b');
  147.                 --ttcol;
  148.                 --cpos;
  149.                 TTflush();
  150.             }
  151.  
  152.         } else if (c == 0x15) {    /* C-U, kill */
  153.             while (cpos != 0) {
  154.                 TTputc('\b');
  155.                 TTputc(' ');
  156.                 TTputc('\b');
  157.                 --cpos;
  158.                 --ttcol;
  159.             }
  160.  
  161.             TTflush();
  162.  
  163.         } else if (c == ' ') {
  164. /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  165.     /* attempt a completion */
  166.     buf[cpos] = 0;        /* terminate it for us */
  167.     ffp = &names[0];    /* scan for matches */
  168.     while (ffp->n_func != NULL) {
  169.         if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
  170.             /* a possible match! More than one? */
  171.             if ((ffp + 1)->n_func == NULL ||
  172.                (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
  173.                 /* no...we match, print it */
  174.                 sp = ffp->n_name + cpos;
  175.                 while (*sp)
  176.                     TTputc(*sp++);
  177.                 TTflush();
  178.                 return(ffp->n_func);
  179.             } else {
  180. /* << << << << << << << << << << << << << << << << << */
  181.     /* try for a partial match against the list */
  182.  
  183.     /* first scan down until we no longer match the current input */
  184.     lffp = (ffp + 1);
  185.     while ((lffp+1)->n_func != NULL) {
  186.         if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0)
  187.             break;
  188.         ++lffp;
  189.     }
  190.  
  191.     /* and now, attempt to partial complete the string, char at a time */
  192.     while (TRUE) {
  193.         /* add the next char in */
  194.         buf[cpos] = ffp->n_name[cpos];
  195.  
  196.         /* scan through the candidates */
  197.         cffp = ffp + 1;
  198.         while (cffp <= lffp) {
  199.             if (cffp->n_name[cpos] != buf[cpos])
  200.                 goto onward;
  201.             ++cffp;
  202.         }
  203.  
  204.         /* add the character */
  205.         TTputc(buf[cpos++]);
  206.     }
  207. /* << << << << << << << << << << << << << << << << << */
  208.             }
  209.         }
  210.         ++ffp;
  211.     }
  212.  
  213.     /* no match.....beep and onward */
  214.     TTbeep();
  215. onward:;
  216.     TTflush();
  217. /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  218.         } else {
  219.             if (cpos < NSTRING-1 && c > ' ') {
  220.                 buf[cpos++] = c;
  221.                 TTputc(c);
  222.             }
  223.  
  224.             ++ttcol;
  225.             TTflush();
  226.         }
  227.     }
  228. }
  229.  
  230. /*    tgetc:    Get a key from the terminal driver, resolve any keyboard
  231.         macro action                    */
  232.  
  233. int tgetc()
  234.  
  235. {
  236.     int c;    /* fetched character */
  237.  
  238.     /* if we are playing a keyboard macro back, */
  239.     if (kbdmode == PLAY) {
  240.  
  241.         /* if there is some left... */
  242.         if (kbdptr < kbdend)
  243.             return((int)*kbdptr++);
  244.  
  245.         /* at the end of last repitition? */
  246.         if (--kbdrep < 1) {
  247.             kbdmode = STOP;
  248. #if    VISMAC == 0
  249.             /* force a screen update after all is done */
  250.             update(FALSE);
  251. #endif
  252.         } else {
  253.  
  254.             /* reset the macro to the begining for the next rep */
  255.             kbdptr = &kbdm[0];
  256.             return((int)*kbdptr++);
  257.         }
  258.     }
  259.  
  260.     /* fetch a character from the terminal driver */
  261.     c = TTgetc();
  262.  
  263.     /* save it if we need to */
  264.     if (kbdmode == RECORD) {
  265.         *kbdptr++ = c;
  266.         kbdend = kbdptr;
  267.  
  268.         /* don't overrun the buffer */
  269.         if (kbdptr == &kbdm[NKBDM - 1]) {
  270.             kbdmode = STOP;
  271.             TTbeep();
  272.         }
  273.     }
  274.  
  275.     /* and finally give the char back */
  276.     return(c);
  277. }
  278.  
  279. /*    GET1KEY:    Get one keystroke. The only prefixs legal here
  280.             are the SPEC and CTRL prefixes.
  281.                                 */
  282.  
  283. get1key()
  284.  
  285. {
  286.     int    c;
  287. #if    AMIGA
  288.     int    d;
  289. #endif
  290.  
  291.     /* get a keystroke */
  292.         c = tgetc();
  293.  
  294. #if    MSDOS | ST520
  295.     if (c == 0) {                /* Apply SPEC prefix    */
  296.             c = tgetc();
  297.             if (c>=0x00 && c<=0x1F)        /* control key? */
  298.                     c = CTRL | (c+'@');
  299.         return(SPEC | c);
  300.     }
  301. #endif
  302.  
  303. #if    AMIGA
  304.     /* apply SPEC prefix */
  305.     if ((unsigned)c == 155) {
  306.         c = tgetc();
  307.  
  308.         /* first try to see if it is a cursor key */
  309.         if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T')
  310.             return(SPEC | c);
  311.  
  312.         /* next, a 2 char sequence */
  313.         d = tgetc();
  314.         if (d == '~')
  315.             return(SPEC | c);
  316.  
  317.         /* decode a 3 char sequence */
  318.         c = d + 32;
  319.         /* if a shifted function key, eat the tilde */
  320.         if (d >= '0' && d <= '9')
  321.             d = tgetc();
  322.         return(SPEC | c);
  323.     }
  324. #endif
  325.  
  326. #if  WANGPC
  327.     if (c == 0x1F) {            /* Apply SPEC prefix    */
  328.             c = tgetc();
  329.         return(SPEC | c);
  330.     }
  331. #endif
  332.  
  333.         if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
  334.                 c = CTRL | (c+'@');
  335.         return (c);
  336. }
  337.  
  338. /*    GETCMD:    Get a command from the keyboard. Process all applicable
  339.         prefix keys
  340.                             */
  341. getcmd()
  342.  
  343. {
  344.     int c;        /* fetched keystroke */
  345.  
  346.     /* get initial character */
  347.     c = get1key();
  348.  
  349.     /* process META prefix */
  350.     if (c == metac) {
  351.         c = get1key();
  352.             if (islower(c))        /* Force to upper */
  353.                     c ^= DIFCASE;
  354.             if (c>=0x00 && c<=0x1F)        /* control key */
  355.                 c = CTRL | (c+'@');
  356.         return(META | c);
  357.     }
  358.  
  359.     /* process CTLX prefix */
  360.     if (c == ctlxc) {
  361.         c = get1key();
  362.             if (c>='a' && c<='z')        /* Force to upper */
  363.                     c -= 0x20;
  364.             if (c>=0x00 && c<=0x1F)        /* control key */
  365.                 c = CTRL | (c+'@');
  366.         return(CTLX | c);
  367.     }
  368.  
  369.     /* otherwise, just return it */
  370.     return(c);
  371. }
  372.  
  373. /*    A more generalized prompt/reply function allowing the caller
  374.     to specify the proper terminator. If the terminator is not
  375.     a return ('\n') it will echo as "<NL>"
  376.                             */
  377. getstring(prompt, buf, nbuf, eolchar)
  378.  
  379. char *prompt;
  380. char *buf;
  381. int eolchar;
  382.  
  383. {
  384.     register int cpos;    /* current character position in string */
  385.     register int c;
  386.     register int quotef;    /* are we quoting the next char? */
  387.  
  388.     cpos = 0;
  389.     quotef = FALSE;
  390.  
  391.     /* prompt the user for the input string */
  392.     mlwrite(prompt);
  393.  
  394.     for (;;) {
  395.         /* get a character from the user */
  396.         c = get1key();
  397.  
  398.         /* If it is a <ret>, change it to a <NL> */
  399.         if (c == (CTRL | 0x4d))
  400.             c = CTRL | 0x40 | '\n';
  401.  
  402.         /* if they hit the line terminate, wrap it up */
  403.         if (c == eolchar && quotef == FALSE) {
  404.             buf[cpos++] = 0;
  405.  
  406.             /* clear the message line */
  407.             mlwrite("");
  408.             TTflush();
  409.  
  410.             /* if we default the buffer, return FALSE */
  411.             if (buf[0] == 0)
  412.                 return(FALSE);
  413.  
  414.             return(TRUE);
  415.         }
  416.  
  417.         /* change from command form back to character form */
  418.         c = ectoc(c);
  419.  
  420.         if (c == ectoc(abortc) && quotef == FALSE) {
  421.             /* Abort the input? */
  422.             ctrlg(FALSE, 0);
  423.             TTflush();
  424.             return(ABORT);
  425.         } else if ((c==0x7F || c==0x08) && quotef==FALSE) {
  426.             /* rubout/erase */
  427.             if (cpos != 0) {
  428.                 outstring("\b \b");
  429.                 --ttcol;
  430.  
  431.                 if (buf[--cpos] < 0x20) {
  432.                     outstring("\b \b");
  433.                     --ttcol;
  434.                 }
  435.  
  436.                 if (buf[cpos] == '\n') {
  437.                     outstring("\b\b  \b\b");
  438.                     ttcol -= 2;
  439.                 }
  440.                 TTflush();
  441.             }
  442.  
  443.         } else if (c == 0x15 && quotef == FALSE) {
  444.             /* C-U, kill */
  445.             while (cpos != 0) {
  446.                 outstring("\b \b");
  447.                 --ttcol;
  448.  
  449.                 if (buf[--cpos] < 0x20) {
  450.                     outstring("\b \b");
  451.                     --ttcol;
  452.                 }
  453.             }
  454.             TTflush();
  455.  
  456.         } else if (c == quotec && quotef == FALSE) {
  457.             quotef = TRUE;
  458.         } else {
  459.             quotef = FALSE;
  460.             if (cpos < nbuf-1) {
  461.                 buf[cpos++] = c;
  462.  
  463.                 if ((c < ' ') && (c != '\n')) {
  464.                     outstring("^");
  465.                     ++ttcol;
  466.                     c ^= 0x40;
  467.                 }
  468.  
  469.                 if (c != '\n')
  470.                     TTputc(c);
  471.                 else {    /* put out <NL> for <ret> */
  472.                     outstring("<NL>");
  473.                     ttcol += 3;
  474.                 }
  475.                 ++ttcol;
  476.                 TTflush();
  477.             }
  478.         }
  479.     }
  480. }
  481.  
  482. outstring(s)    /* output a string of characters */
  483.  
  484. char *s;    /* string to output */
  485.  
  486. {
  487.     while (*s)
  488.         TTputc(*s++);
  489. }
  490.